package co.edu.uniandes.ecos.itera.tsp.mundo;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import co.edu.uniandes.ecos.itera.tsp.anotaciones.*;

@Tiempos( { @LogT(date = "2011-03-20", min = 60, taskId = 77),
		@LogT(date = "2011-03-20", min = 61, taskId = 77),
		@LogT(date = "2011-03-20", min = 60, taskId = 77),
		@LogT(date = "2011-03-26", min = 10, taskId = 130) })
@Interrupciones( {
		@LogInt(date = "2011-03-20", intId = 7, min = 60, taskId = 77),
		@LogInt(date = "2011-03-20", intId = 6, min = 20, taskId = 77) })
@Avance(taskId = 77, termino = 'S')
public class EntidadReporteCalidad {
	// reovidos
	private Hashtable<Desarrollador, Hashtable<Etapa, Integer>> totalDefectosXDesarrollador = new Hashtable<Desarrollador, Hashtable<Etapa, Integer>>();
	// inyectados
	private Hashtable<Desarrollador, Hashtable<Etapa, Integer>> totalDefectosInyectadosXDesarrollador = new Hashtable<Desarrollador, Hashtable<Etapa, Integer>>();

	// removidos
	private Hashtable<Etapa, Integer> totalDefectosXGrupo = new Hashtable<Etapa, Integer>();
	// inyectados
	private Hashtable<Etapa, Integer> totalDefectosInyectadosXGrupo = new Hashtable<Etapa, Integer>();

	// incluye yield
	private Hashtable<Desarrollador, Integer> resultadoDefectosXDesarrollador = new Hashtable<Desarrollador, Integer>();

	private int yieldGrupo = 100;
	private Integer totalLineasCodigoGrupo = 0;
	private Hashtable<Desarrollador, Integer> totalLineasDesarrollador;
	private PlanCalidad plan;

	@Loc(size = 98, taskId = 77)
	public EntidadReporteCalidad generarReporte(Ciclo ciclo) {
		// 1. recorrer los defectos

		List<Desarrollador> desarrolladoresDelProyecto = new ArrayList<Desarrollador>();
		if (ciclo != null) {
			List<Tarea> tareas = ciclo.listarTareas();
			// plan = ciclo.getPlanCalidad();

			if (tareas != null) {
				totalLineasDesarrollador = new Hashtable<Desarrollador, Integer>();

				for (Tarea tarea : tareas) {
					totalLineasCodigoGrupo += tarea.getLineasDeCodigoReales();

					Desarrollador desarrollador = tarea.getDesarrollador();
					if (totalLineasDesarrollador.get(desarrollador) != null) {
						Integer totalActual = totalLineasDesarrollador
								.get(desarrollador);
						totalActual += tarea.getLineasDeCodigoReales();
						totalLineasDesarrollador
								.put(desarrollador, totalActual);

					} else {
						totalLineasDesarrollador.put(desarrollador, tarea
								.getLineasDeCodigoReales());
					}
					if (!desarrolladoresDelProyecto.contains(desarrollador))
						desarrolladoresDelProyecto.add(desarrollador);
					/*
					 * obtiene los defectos por tarea, la tarea pertenece a una
					 * fase. el defecto, a su vez indica el total
					 */
					Hashtable<Defecto, Hashtable<Etapa, Integer>> defectosTareas = tarea
							.listarDefectos();

					Enumeration<Defecto> defectos = defectosTareas.keys();

					if (defectos != null) {
						while (defectos.hasMoreElements()) {

							Defecto defecto = defectos.nextElement();
							/*
							 * Cuenta los defectos removidos en esta tarea
							 * perteneciente a una fase establecida para un
							 * desarrollador particular
							 */
							if (desarrollador != null) {
								Hashtable<Etapa, Integer> tmpDefectosPorEtapa = totalDefectosXDesarrollador
										.get(desarrollador);
								if (tmpDefectosPorEtapa != null) {
									if (tmpDefectosPorEtapa.get(tarea
											.getEtapa()) != null) {
										int contadorDefectosXDesarrolladorFase = tmpDefectosPorEtapa
												.get(tarea.getEtapa());
										contadorDefectosXDesarrolladorFase++;
										tmpDefectosPorEtapa
												.put(tarea.getEtapa(),
														contadorDefectosXDesarrolladorFase);
										totalDefectosXDesarrollador.put(
												desarrollador,
												tmpDefectosPorEtapa);

									} else {
										tmpDefectosPorEtapa = new Hashtable<Etapa, Integer>();
										tmpDefectosPorEtapa.put(tarea
												.getEtapa(), 1);
										totalDefectosXDesarrollador.put(
												desarrollador,
												tmpDefectosPorEtapa);
									}
								}
							}

							/*
							 * Cuenta los defectos inyectados en esta tarea
							 * perteneciente a una fase establecida para un
							 * desarrollador particular
							 */
							if (desarrollador != null) {
								// obtiene las etabas en las que se inyecto este
								// tipo de defecto
								Hashtable<Etapa, Integer> tmpDefectosPorEtapa = defectosTareas
										.get(defecto);
								// sumatiria de la etapa
								Hashtable<Etapa, Integer> tmp2DefectosPorEtapa = new Hashtable<Etapa, Integer>();
								// recorrelas etapas
								Enumeration<Etapa> fases = tmpDefectosPorEtapa
										.keys();
								// para este tipo de error cuento el numero de
								// inyectados por fase
								while (fases.hasMoreElements()) {
									Etapa fase = fases.nextElement();
									if (tmpDefectosPorEtapa.get(fase) != null) {
										// total de defectos ya registrados en
										// esta fase para este tipo defecto
										int contadorDefectosInyectadosXDesarrolladorFase = tmpDefectosPorEtapa
												.get(fase) != null ? tmpDefectosPorEtapa
												.get(fase)
												: 0;
										int contadorActual = tmp2DefectosPorEtapa
												.get(fase) != null ? tmp2DefectosPorEtapa
												.get(fase)
												: 0;

										tmp2DefectosPorEtapa
												.put(
														fase,
														(contadorDefectosInyectadosXDesarrolladorFase + contadorActual));
										totalDefectosInyectadosXDesarrollador
												.put(desarrollador,
														tmp2DefectosPorEtapa);
									} else {
										tmp2DefectosPorEtapa.put(fase,
												tmpDefectosPorEtapa.get(fase));
										totalDefectosInyectadosXDesarrollador
												.put(desarrollador,
														tmp2DefectosPorEtapa);
									}
								}
							}
							/*
							 * Cuenta los defectos removidos del grupo en
							 * general
							 */
							if (totalDefectosXGrupo.get(tarea.getEtapa()) != null) {
								int contadorDefectosXGrupoFase = totalDefectosXGrupo
										.get(tarea.getEtapa());

								contadorDefectosXGrupoFase++;
								totalDefectosXGrupo.put(tarea.getEtapa(),
										contadorDefectosXGrupoFase);

							} else {
								totalDefectosXGrupo.put(tarea.getEtapa(), 1);

							}

							/*
							 * Cuenta los defectos inyectados en esta tarea
							 * perteneciente a una fase establecida para el
							 * grupo particular
							 */
							// obtiene las etabas en las que se inyecto este
							// tipo de defecto
							Hashtable<Etapa, Integer> tmpDefectosPorEtapa = defectosTareas
									.get(defecto);
							// sumatoria de la etapa
							Hashtable<Etapa, Integer> tmp2DefectosPorEtapa = new Hashtable<Etapa, Integer>();
							// recorrelas etapas
							Enumeration<Etapa> fases = tmpDefectosPorEtapa
									.keys();
							// para este tipo de error cuento el numero de
							// inyectados por fase
							while (fases.hasMoreElements()) {
								Etapa fase = fases.nextElement();
								if (tmpDefectosPorEtapa.get(fase) != null) {
									// total de defectos ya registrados en esta
									// fase para este tipo defecto
									int contadorDefectosInyectadosFase = totalDefectosInyectadosXGrupo
											.get(fase) != null ? totalDefectosInyectadosXGrupo
											.get(fase)
											: 0;
									int contadorActual = tmp2DefectosPorEtapa
											.get(fase) != null ? tmp2DefectosPorEtapa
											.get(fase)
											: 0;

									totalDefectosInyectadosXGrupo
											.put(
													fase,
													(contadorDefectosInyectadosFase + contadorActual));
								} else {
									totalDefectosInyectadosXGrupo.put(fase,
											tmpDefectosPorEtapa.get(fase));
								}
							}

						}
					}
				}
			}

			// calculo yield por desarrollador:
			Enumeration<Desarrollador> desarrolladores = totalDefectosXDesarrollador
					.keys();
			int yGrupo = 0;
			while (desarrolladores.hasMoreElements()) {

				Desarrollador des = desarrolladores.nextElement();
				int yDes = this.calcularYield(totalDefectosXDesarrollador
						.get(des), totalDefectosInyectadosXDesarrollador
						.get(des));
				yGrupo += yDes;
				resultadoDefectosXDesarrollador.put(des, yDes);

			}
			if (desarrolladoresDelProyecto != null
					&& desarrolladoresDelProyecto.size() > 0)
				yieldGrupo = yGrupo / desarrolladoresDelProyecto.size();

		}

		/*
		 * Genera el resumen de acuerdo a lo real:
		 */
		return this;
	}

	public int calcularYield(Hashtable<Etapa, Integer> inyectados,
			Hashtable<Etapa, Integer> removidos) {
		int yield = 0;
		int acumulado = 0;
		int totalDefectosInyectados = totalDefectos(inyectados);
		if (totalDefectosInyectados > 0 && removidos != null) {
			Enumeration<Etapa> etapasRemovidas = removidos.keys();
			if (etapasRemovidas != null) {
				while (etapasRemovidas.hasMoreElements()) {
					Etapa etapaRemovida = etapasRemovidas.nextElement();

					int valorReal = removidos.get(etapaRemovida) != null ? removidos
							.get(etapaRemovida)
							: 0;

					acumulado += (valorReal * 100) / totalDefectosInyectados;

				}
			}
			yield = acumulado / 6;
		} else
			yield = 100;

		return yield;

	}

	private int totalDefectos(Hashtable<Etapa, Integer> porFase) {

		int totalDefectos = 0;
		if (porFase != null) {
			Enumeration<Etapa> etapasPlaneadas = porFase.keys();
			if (etapasPlaneadas != null) {
				while (etapasPlaneadas.hasMoreElements()) {
					Etapa etapaPlaneada = etapasPlaneadas.nextElement();
					int valorPlaneado = porFase.get(etapaPlaneada) != null ? porFase
							.get(etapaPlaneada)
							: 0;

					totalDefectos += valorPlaneado;

				}
			}
		}

		return totalDefectos;
	}

	public Hashtable<Desarrollador, Hashtable<Etapa, Integer>> getTotalDefectosXDesarrollador() {
		return totalDefectosXDesarrollador;
	}

	void setTotalDefectosXDesarrollador(
			Hashtable<Desarrollador, Hashtable<Etapa, Integer>> totalDefectosXDesarrollador) {
		this.totalDefectosXDesarrollador = totalDefectosXDesarrollador;
	}

	public Hashtable<Desarrollador, Hashtable<Etapa, Integer>> getTotalDefectosInyectadosXDesarrollador() {
		return totalDefectosInyectadosXDesarrollador;
	}

	void setTotalDefectosInyectadosXDesarrollador(
			Hashtable<Desarrollador, Hashtable<Etapa, Integer>> totalDefectosInyectadosXDesarrollador) {
		this.totalDefectosInyectadosXDesarrollador = totalDefectosInyectadosXDesarrollador;
	}

	public Hashtable<Etapa, Integer> getTotalDefectosXGrupo() {
		return totalDefectosXGrupo;
	}

	void setTotalDefectosXGrupo(Hashtable<Etapa, Integer> totalDefectosXGrupo) {
		this.totalDefectosXGrupo = totalDefectosXGrupo;
	}

	public Hashtable<Etapa, Integer> getTotalDefectosInyectadosXGrupo() {
		return totalDefectosInyectadosXGrupo;
	}

	void setTotalDefectosInyectadosXGrupo(
			Hashtable<Etapa, Integer> totalDefectosInyectadosXGrupo) {
		this.totalDefectosInyectadosXGrupo = totalDefectosInyectadosXGrupo;
	}

	public Hashtable<Desarrollador, Integer> getResultadoDefectosXDesarrollador() {
		return resultadoDefectosXDesarrollador;
	}

	void setResultadoDefectosXDesarrollador(
			Hashtable<Desarrollador, Integer> resultadoDefectosXDesarrollador) {
		this.resultadoDefectosXDesarrollador = resultadoDefectosXDesarrollador;
	}

	public int getYieldGrupo() {
		return yieldGrupo;
	}

	void setYieldGrupo(int yieldGrupo) {
		this.yieldGrupo = yieldGrupo;
	}

	public PlanCalidad getPlan() {
		return plan;
	}

	void setPlan(PlanCalidad plan) {
		this.plan = plan;
	}

	public Integer getTotalLineasCodigoGrupo() {
		return totalLineasCodigoGrupo;
	}

	void setTotalLineasCodigoGrupo(Integer totalLineasCodigoGrupo) {
		this.totalLineasCodigoGrupo = totalLineasCodigoGrupo;
	}

	@Loc(size = 2, taskId = 1)
	public Hashtable<Desarrollador, Integer> getTotalLineasDesarrollador() {
		return totalLineasDesarrollador;
	}

	@Loc(size = 2, taskId = 1)
	void setTotalLineasDesarrollador(
			Hashtable<Desarrollador, Integer> totalLineasDesarrollador) {
		this.totalLineasDesarrollador = totalLineasDesarrollador;
	}

}
